package es.official.guide.modeling; import java.io.IOException; import java.util.Arrays; import java.util.Map; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram.Interval; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.junit.Test; import es.ESTestBase; /** * http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/nested-mapping.html * http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/nested-query.html * http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/nested-sorting.html */ public class NestedObjectMappingExamples extends ESTestBase { private String indexName = "nested"; private String typeName = "blogpost"; @Test public void testCreateIndex() throws IOException { CreateIndexRequestBuilder cirb = client.admin().indices().prepareCreate(indexName).setSource(XContentFactory.jsonBuilder() .startObject() .startObject("settings") .field("number_of_shards", 1) .field("number_of_replicas", 0) .endObject() .endObject()); CreateIndexResponse response = cirb.execute().actionGet(); if(response.isAcknowledged()) { System.out.println("Index created."); } else { System.err.println("Index creation failed."); } } @Test public void testCreateNestedMapping() throws IOException { // if the setType is used, then the startObject("mapping") is not necessary PutMappingResponse response = client.admin().indices().preparePutMapping(indexName).setType(typeName).setSource(XContentFactory.jsonBuilder() .startObject() // .startObject("mappings") .startObject(typeName) .startObject("properties") .startObject("comments") .field("type", "nested") .startObject("properties") // field name .startObject("name") .field("type", "string") .endObject() // field comment .startObject("comment") .field("type", "string") .endObject() // field age .startObject("age") .field("type", "short") .endObject() // field stars .startObject("stars") .field("type", "short") .endObject() // field date .startObject("date") .field("type", "date") .endObject() .endObject() .endObject() .endObject() .endObject() // .endObject() .endObject()).execute().actionGet(); // read mapping response if(response.isAcknowledged()) { System.out.println("Create mapping with nested type succeeded."); } else { System.err.println("Create mapping with nested type failed."); } } @Test public void testIndexNestedDocument() throws IOException { // creating json contained array: // http://stackoverflow.com/questions/10170053/how-to-index-an-array-of-nested-type-in-elasticsearch IndexRequestBuilder irb = client.prepareIndex(indexName, typeName, "1").setSource(XContentFactory.jsonBuilder() .startObject() .field("title", "Nest eggs") .field("body", "Making your money work...") .field("tags", "cash", "shares") .startArray("comments") // 1st comment .startObject() .field("name", "John Smith") .field("comment", "Great article") .field("age", 28) .field("stars", 4) .field("date", "2014-09-01") .endObject() // 2nd comment .startObject() .field("name", "Alice White") .field("comment", "More like this please") .field("age", 31) .field("stars", 5) .field("date", "2014-10-22") .endObject() .endArray() .endObject()); IndexResponse response = irb.execute().actionGet(); if(response.isCreated()) { System.out.println("Creating nested document succeeded."); } else { System.err.println("Creating nested document failed."); } } @Test public void testQueryNestedDocument() { SearchResponse response = client.prepareSearch(indexName).setTypes(typeName).setQuery(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("title", "eggs")) .must(QueryBuilders.nestedQuery("comments", QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("comments.name", "john")) .must(QueryBuilders.matchQuery("comments.age", 28))))).execute().actionGet(); // read response SearchHit[] hits = response.getHits().getHits(); Arrays.asList(hits).forEach(hit -> { Map<String, Object> source = hit.getSource(); Object object = source.get("comments"); System.out.println(object); // java.util.ArrayList System.out.println(object.getClass().getName()); // score when the score mode is the default(average) System.out.println("Score by average: " + hit.getScore()); }); } @Test public void testQueryNestedDocumentWithScoreMode() { SearchResponse response = client.prepareSearch(indexName).setTypes(typeName).setQuery(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("title", "eggs")) .must(QueryBuilders.nestedQuery("comments", QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("comments.name", "john")) .must(QueryBuilders.matchQuery("comments.age", 28))).scoreMode("max"))).execute().actionGet(); // read response SearchHit[] hits = response.getHits().getHits(); Arrays.asList(hits).forEach(hit -> { Map<String, Object> source = hit.getSource(); Object object = source.get("comments"); System.out.println(object); // score when the score mode is the max System.out.println("Score by max: " + hit.getScore()); }); } // GET /nested/blogpost/_search // { // "query": { // "nested": { // "path": "comments", // "filter": { // "range": { // "comments.date": { // "gte": "2014-10-01", // "lt": "2014-11-01" // } // } // } // } // }, // "sort": { // "comments.stars": { // "order": "asc", // "mode": "min", // "nested_filter": { // "range": { // "comments.date": { // "gte": "2014-10-01", // "lt": "2014-11-01" // } // } // } // } // } // } @Test public void testQueryWithSortingOnNested() { SearchResponse response = client.prepareSearch(indexName).setTypes(typeName).setQuery( QueryBuilders.nestedQuery("comments", FilterBuilders.rangeFilter("comments.date") .gte("2014-10-01").lt("2014-11-01"))) .addSort(SortBuilders.fieldSort("comments.stars").order(SortOrder.ASC).sortMode("min") .setNestedFilter(FilterBuilders.rangeFilter("comments.date").gte("2014-10-01").lt("2014-11-01"))) .execute().actionGet(); // read response System.out.println(response); } // GET /nested/blogpost/_search?search_type=count // { // "aggs": { // "comments": { // "nested": { // "path": "comments" // }, // "aggs": { // "by_month": { // "date_histogram": { // "field": "comments.date", // "interval": "month", // "format": "yyyy-MM" // }, // "aggs": { // "avg_stars": { // "avg": { // "field": "comments.stars" // } // } // } // } // } // } // } // } @Test public void testQueryWithAggOnNested() { String aggOnComments = "comments", aggOnMonths = "by_month", aggOnAvgStars = "avg_stars"; SearchResponse response = client.prepareSearch(indexName).setTypes(typeName).setSearchType(SearchType.COUNT) .addAggregation(AggregationBuilders.nested(aggOnComments).path(aggOnComments) .subAggregation(AggregationBuilders.dateHistogram(aggOnMonths).field("comments.date").interval(Interval.MONTH).format("yyyy-MM") .subAggregation(AggregationBuilders.avg(aggOnAvgStars).field("comments.stars"))) ).execute().actionGet(); // read response and agg System.out.println(response); } // GET /nested/blogpost/_search?search_type=count // { // "aggs": { // "comments": { // "nested": { // "path": "comments" // }, // "aggs": { // "age_group": { // "histogram": { // "field": "comments.age", // "interval": 10 // }, // "aggs": { // "blogposts": { // "reverse_nested": {}, // "aggs": { // "tags": { // "terms": { // "field": "tags" // } // } // } // } // } // } // } // } // } // } @Test public void testQueryWithReverseAggOnNested() { String comments = "comments", ageGroup = "age_group", blogposts = "blogposts"; SearchResponse response = client.prepareSearch(indexName).setTypes(typeName).setSearchType(SearchType.COUNT) .addAggregation(AggregationBuilders.nested(comments).path(comments) .subAggregation(AggregationBuilders.histogram(ageGroup).field("comments.age").interval(10) .subAggregation(AggregationBuilders.reverseNested(blogposts) .subAggregation(AggregationBuilders.terms("tags").field("tags"))))).execute().actionGet(); System.out.println(response); } }